package com.pro.common.modules.service.dependencies.util;

import cn.hutool.core.util.BooleanUtil;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.pro.framework.api.clazz.ClassCaches;
import com.pro.framework.api.model.IModelHasUpdate;
import com.pro.framework.api.structure.Tuple2;
import com.pro.framework.api.structure.Tuple3;
import com.pro.framework.api.util.AssertUtil;
import com.pro.framework.api.util.BeanUtils;
import com.pro.framework.api.util.CollUtils;
import com.pro.framework.api.util.Fn;
import com.pro.framework.mybatisplus.BaseService;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.*;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.stream.Stream;

public class EntityUtil {

//    /**
//     * 副表(相对于主表) 实现 新增/更新/删除 按顺序处理,的准备工作
//     * 新增 id 为空
//     * 修复 id 改为旧值
//     * 删除 removeByIds
//     *
//     * @param entityListMapNew 副表按主表id分组后的对象map
//     * @param service          副表service
//     * @param relationField    副表与按主表id的关联字段
//     */
//    public static <ENTITY extends IModelHasUpdate, SERVICE extends BaseService<?, ENTITY>> void saveOrUpdateBatch(List<ENTITY> list, SERVICE service) {
//        service.saveOrUpdateBatch();
//    }

    /**
     *
     */
    @SuppressWarnings("rawtypes")
    public static <ENTITY extends IModelHasUpdate, SERVICE extends BaseService<?, ENTITY>, KEY> void queryOldThenSaveOrUpdateBatch(List<ENTITY> entityNews, SERVICE service, SFunction<ENTITY, KEY> keyFun) {

        // 查询旧数据
        List<KEY> keys = entityNews.stream().map(keyFun).toList();
        Map<KEY, ENTITY> oldKeyMap = service.getMap(keyFun, keys, keyFun);
        queryOldThenSaveOrUpdateBatch(entityNews, oldKeyMap.values().stream().toList(), service, keyFun);
    }

    /**
     *
     */
    @SuppressWarnings("rawtypes")
    public static <ENTITY extends IModelHasUpdate, SERVICE extends BaseService<?, ENTITY>, KEY> void queryOldThenSaveOrUpdateBatch(List<ENTITY> entityNews, List<ENTITY> entityOlds, SERVICE service, SFunction<ENTITY, KEY> keyFun) {

        // 查询旧数据
        Map<KEY, ENTITY> oldKeyMap = CollUtils.listToMap(entityOlds, keyFun);
        List<Tuple2<ENTITY, ENTITY>> tuple2s = new ArrayList<>();

        for (ENTITY entityNew : entityNews) {
            ENTITY entityOld = oldKeyMap.get(keyFun.apply(entityNew));
            // 构造update对象  (没变化的属性不修改)
            tuple2s.add(new Tuple2<>(BeanUtils.buildSaveOrUpdate(entityOld, entityNew), entityNew));
        }

        // 新增/修改
        service.saveOrUpdateBatch(tuple2s.stream().map(Tuple2::getT1).filter(o -> BooleanUtil.isTrue(o.getHasUpdate())).toList());
        // id回填
        tuple2s.forEach(tuple2 -> tuple2.getT2().setId(tuple2.getT1().getId()));
    }

    /**
     * 副表(相对于主表) 实现 新增/更新/删除 按顺序处理,的准备工作
     * 新增 id 为空
     * 修复 id 改为旧值
     * 删除 removeByIds
     *
     * @param entityListMapNew 副表按主表id分组后的对象map
     * @param service          副表service
     * @param relationField    副表与按主表id的关联字段
     */
    @SuppressWarnings("rawtypes")
    public static <ENTITY extends IModelHasUpdate, SERVICE extends BaseService<?, ENTITY>> void queryOldThenSaveOrUpdateBatchRemove(Map<Long, List<ENTITY>> entityListMapNew, SERVICE service, SFunction<ENTITY, Long> relationField, SFunction<ENTITY, ?> outKeyField) {
        queryOldThenSaveOrUpdateBatchRemove(entityListMapNew, service, relationField, outKeyField, (objNew, objOld) -> true);
    }

    @SuppressWarnings("rawtypes")
    public static <ENTITY extends IModelHasUpdate, SERVICE extends BaseService<?, ENTITY>> void queryOldThenSaveOrUpdateBatchRemove(Map<Long, List<ENTITY>> entityListMapNew, SERVICE service, SFunction<ENTITY, Long> relationField, SFunction<ENTITY, ?> outKeyField, BiFunction<ENTITY, ENTITY, Boolean> filter) {
        // 新增 / 更新 / 删除 旧数据
        List<Long> entityIdsToRemoveOld = new ArrayList<>();
        List<Tuple2<ENTITY, ENTITY>> tuple2s = new ArrayList<>();

        // 查询旧数据
        Map<Long, List<ENTITY>> entityListMapOld = service.getListMap(relationField, entityListMapNew.keySet());
        entityListMapNew.forEach((groupId, entitiesNew) -> {
            List<ENTITY> entitiesOld = entityListMapOld.getOrDefault(groupId, Collections.emptyList());
            List<ENTITY> repeats = new ArrayList<>();
            Map<?, ENTITY> entityOldMap = CollUtils.listToMapAllRight(entitiesOld, outKeyField, repeats);
            for (ENTITY entityNew : entitiesNew) {
                ENTITY entityOld = entityOldMap.get(outKeyField.apply(entityNew));
                if (filter.apply(entityNew, entityOld)) {
                    tuple2s.add(new Tuple2<>(BeanUtils.buildSaveOrUpdate(entityOld, entityNew), entityNew));
                }
            }

            Map<?, ENTITY> entityNewMap = CollUtils.listToMap(entitiesNew, outKeyField);
            entitiesOld.forEach(entityOld -> {
                ENTITY entityNew = entityNewMap.get(outKeyField.apply(entityOld));
                if (filter.apply(entityNew, entityOld)) {
                    if (entityNew == null) {
                        entityIdsToRemoveOld.add(entityOld.getId());
                    }
                }
            });
            repeats.forEach(repeat -> entityIdsToRemoveOld.add(repeat.getId()));
        });

        // 删除
        service.removeByIds(entityIdsToRemoveOld);
        // 新增/修改
        service.saveOrUpdateBatch(tuple2s.stream().map(Tuple2::getT1).filter(o -> BooleanUtil.isTrue(o.getHasUpdate())).toList());
        // id回填
        tuple2s.forEach(tuple2 -> tuple2.getT2().setId(tuple2.getT1().getId()));
    }

    public static <T, R> List<R> props(List<T> list, Function<T, R> function) {
        return list.stream().map(function).distinct().toList();
    }

    /**
     * 为 null 0  空字符串  经常判断为没有有效值
     */
    public static boolean isBusinessEmpty(Object targeValue) {
        if (targeValue instanceof Integer) {
            return ((Integer) targeValue) == 0;
        }
        if (targeValue instanceof BigDecimal) {
            return ((BigDecimal) targeValue).compareTo(BigDecimal.ZERO) == 0;
        }
        return null == targeValue || "".equals(targeValue);
    }


    /**
     * 从 source 复制字段到 target，使用函数决定是否赋值。 同名属性
     *
     * @param source      源对象
     * @param target      目标对象
     * @param needCopyFun 四元函数，判断是否赋值：(sourceField, sourceValue, targetField, targetValue) -> Boolean
     */
    public static <SOURCE, TARGET> void copyPropsDefaultValue(SOURCE source, TARGET target, Fn.QuadFunction<Field, Object, Field, Object, Boolean> needCopyFun) {
        if (source == null || target == null || needCopyFun == null) return;

        Map<String, Tuple3<Field, Method, Method>> sourceFieldMap = ClassCaches.getClassInfosAll(source.getClass());
        Map<String, Tuple3<Field, Method, Method>> targetFieldMap = ClassCaches.getClassInfosAll(target.getClass());

        for (Map.Entry<String, Tuple3<Field, Method, Method>> entry : sourceFieldMap.entrySet()) {
            String fieldName = entry.getKey();
            Tuple3<Field, Method, Method> sourceTuple = entry.getValue();
            Tuple3<Field, Method, Method> targetTuple = targetFieldMap.get(fieldName);
            if (targetTuple == null) continue;

            try {
                Object sourceValue = sourceTuple.getT3().invoke(source);
                Object targetValue = targetTuple.getT3().invoke(target);

                Boolean needCopy = needCopyFun.apply(sourceTuple.getT1(), sourceValue, targetTuple.getT1(), targetValue);
                if (Boolean.TRUE.equals(needCopy)) {
                    targetTuple.getT2().invoke(target, sourceValue);
                }
            } catch (Exception e) {
                throw new RuntimeException("copyPorpsDefaultValue error at field: " + fieldName, e);
            }
        }
    }

    /**
     * order 相同 就取新的
     * order 不同 就取order大的
     */
    public static <T, SORT extends Comparable<SORT>> T getOrderMaxOrNew(T newEntity, T oldEntity, Function<T, SORT> getSortFun) {
        if (newEntity == null) {
            return oldEntity;
        }
        if (oldEntity == null) {
            return newEntity;
        }
//        AssertUtil.notEmpty(newEntity, "newEntity must not be null");
//        AssertUtil.notEmpty(oldEntity, "oldEntity must not be null");
        // order 相同就取新的
        if (getSortFun.apply(newEntity).compareTo(getSortFun.apply(oldEntity)) == 0) {
            return newEntity;
        }
        return Stream.of(newEntity, oldEntity).max(Comparator.comparing(getSortFun)).orElse(null);
    }
}
